import * as React from 'react';
import {
  Component,
  PropTypes
} from 'react';
import {appToggleAsideFolded, appToggleAsideNavOpen, sendNotify, appToggleHeaderNavOpen} from '../../actions/asist';
import {connect} from 'react-redux';
import Header from '../../widgets/header/header';
import RequireUser from '../layout/user';
import Aside from '../../widgets/aside/aside';
import Layout from '../layout/index';
import {map, filter as filterTree} from '../../util/tree';
import {filter, evalExpression} from '../renderers/util';
import * as assign from 'object-assign';
import * as shiroTrie from 'shiro-trie';



const pages = [];


export function RegisterPage(config) {
  pages.push(config);
}

export function getPages() {
  return pages.concat();
}

let menus = null;
function getMenus() {
  if (menus) {
    return menus;
  }

  menus = map(pages, item => ({
    label: item.label,
    url: item.url,
    icon: item.icon,
    path: item.path,
    acl: item.acl
  }));

  return menus;
}

function fillParams(path, params) {
  return path.replace(/:(\S+)/g, (_, key) => {
    return params[key] || '__';
  });
}

function markActive(items, currentSubPath, hash = '', params = {}, isActive = (location) => false) {
  let hasActive = false;

  items.forEach(item => {
    let url = item.url;
    let index1 = url ? url.indexOf('?') : -1;
    let index2 = currentSubPath.indexOf('?');
    if (~index1) {
      url = url.substring(0, index1);
    }
    if (~index2) {
      currentSubPath = currentSubPath.substring(0, index2);
    }

    if (typeof item.active === 'undefined') {
      item.childActive = item.children && markActive(item.children, currentSubPath, hash, params, isActive);
      item.active = item.path && isActive({pathname: fillParams(item.path, params), hash: hash}) || currentSubPath === url && (!item.hash || item.hash === hash);
    }

    if (item.active || item.childActive) {
      hasActive = true;
    }
  });

  return hasActive;
}

@RequireUser
@connect(state => ({
  folded: state.assist.asideFolded,
  navOpened: state.assist.asideNavOpened,
  headerNavOpened: state.assist.headerNavOpened,
  unreadCount: state.assist.unread_count
}), {
  appToggleAsideFolded,
  appToggleAsideNavOpen,
  appToggleHeaderNavOpen,
  sendNotify
})
export default class AdminRoot extends Component {
  static propTypes = {
    className: PropTypes.string
  };

  static contextTypes = {
    router: PropTypes.object
  };

  static childContextTypes = {
    can: PropTypes.func
  };


  constructor(props, context) {
    super(props, context);

    const can = this.buildCan(props);
    this.state = {
      menus: this.buildLinkGroups(props, context.router.isActive, can),
      can: can
    };
  }

  getChildContext() {
    return {
      can: this.state.can
    };
  }

  componentWillReceiveProps(nextProps) {
    const props = this.props;

    if (props.location !== nextProps.location) {
      const linkGroups = this.buildLinkGroups(nextProps, this.context.router.isActive, this.state.can);
      this.setState({
        menus: linkGroups
      });
    }


    if (props.user.acl !== nextProps.user.acl) {
      this.setState({
        can: this.buildCan(nextProps)
      });
    }
  }

  buildCan(props) {
    const account = shiroTrie.new();
    props.user.acl.forEach(perm => account.add(perm));
    return can;

    function can(perm) {
      return Array.isArray(perm) ? perm.some(perm => can(perm)) : perm.split('|').some(item => item.split('&').every(perm => account.check(perm.trim())))
    }
  }

  buildLinkGroups(props, isActive, can) {
    const pathname = props.location.pathname;
    const hash = props.location.hash;
    const pages = getMenus();

    let linkGroups = [];
    linkGroups.push({
      // label: '导航',
      children: pages && pages.length ? pages : [
          {
            label: '暂无任何页面',
            url: null
          }
        ]
    });

    // 转换 /url => /admin/url
    linkGroups = map(linkGroups, item => assign({}, item, {
      url: filter(item.url, props.location.query)
    }));

    // 过滤掉没有权限的页面.
    linkGroups = linkGroups.filter(group => group.children && group.children.length);

    let alinkGroups = linkGroups.map(item => {
      if (item.children && item.children.length) {
        const children = assign([], item.children);
        markActive(children, pathname, hash, props.params, isActive);
        item.children = children;
      }
      return item;
    });

    const data = {
      ...props.location.query,
      user: props.user
    };

    return filterTree(alinkGroups, item => {
      if (item.visibleOn && !evalExpression(item.visibleOn, data)) {
        return false;
      } else if (item.hiddenOn && evalExpression(item.hiddenOn, data)) {
        return false;
      }

      if (item.acl && !can(item.acl)) {
        return false;
      }

      return item.url || item.active || item.children;
    });
  }

  render() {
    const {
      appToggleAsideFolded,
      appToggleAsideNavOpen,
      appToggleHeaderNavOpen,
      folded,
      navOpened,
      user,
      children,
      unreadCount,
      headerNavOpened
    } = this.props;

    const brand = [
      <button key="toggleHeader" className="pull-right visible-xs" onClick={appToggleHeaderNavOpen}>
        <i className="glyphicon glyphicon-cog" />
      </button>,

      <button key="toggleAside" className="pull-right visible-xs" onClick={appToggleAsideNavOpen}>
        <i className="glyphicon glyphicon-align-justify" />
      </button>
    ];

    const nav = [
      <div key="nav1" onClick={appToggleAsideFolded} className="nav navbar-nav hidden-xs">
        <a className="btn no-shadow navbar-btn">
          {folded ? (
              <i className="fa fa-indent fa-fw" />
            ) : (
              <i className="fa fa-dedent fa-fw" />
            )}
        </a>
      </div>
    ];

    const linkGroups = this.state.menus;

    const routes = this.props.routes;
    let navComponents = [];
    routes && routes.forEach((route, idx) => {
      if (route.NavComponent && (!route.NavComponentTest || route.NavComponentTest(this.props))) {
        navComponents.push(<route.NavComponent {...this.props} key={`route_${idx}`} wrapperComponent="li" />)
      }
    });

    if (navComponents.length) {
      nav.push(<ul key="nav2" className="nav navbar-nav hidden-sm">{navComponents}</ul>)
    }

    return (
      <Layout
        folded={folded}
        header={(
          <Header
            navOpened={headerNavOpened}
            logo={user.type == 3 && user.org ? user.org.logo : user.type == 2 && user.team ? user.team.logo : ''}
            brandName={user.type == 3 && user.org ? user.org.name : user.type == 2 && user.team ? user.team.name : '志多星'}
            brand={brand} brandLink={`/`}  nav={nav} user={user} unreadCount={unreadCount} />
        )}
        aside={(
          <Aside groups={linkGroups} folded={folded} navOpened={navOpened} />
        )}
        aideFixed
      >
        {React.cloneElement(children, {
          ...children.props,
          data: {
            ...children.props.data,
            user: user
          },
          user: user,
          can: this.state.can
        })}
      </Layout>
    );
  }
}
